package com.ice.body.hardware.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.ice.base.exception.CustomException;
import com.ice.base.model.SysLoginModel;
import com.ice.base.result.AjaxResult;
import com.ice.base.util.*;
import com.ice.body.business.dao.ReagentStockDao;
import com.ice.body.business.model.*;
import com.ice.body.business.service.*;
import com.ice.body.dict.model.SwitchModel;
import com.ice.body.dict.service.SwitchService;
import com.ice.body.hardware.model.DeviceFace;
import com.ice.body.hardware.model.DeviceIo;
import com.ice.body.hardware.model.DeviceVoice;
import com.ice.body.hardware.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@EnableAsync
@Service
public class FaceToRoomServiceImpl implements FaceToRoomService {


    @Resource
    private RedisUtil redisUtil;
    @Resource
    private VoiceUtil voiceUtil;
    @Resource
    private IOUtil ioUtil;
    @Resource
    private FaceLogService faceLogService;
    @Resource
    private DeviceVideoService videoService;
    @Resource
    private DeviceIoService deviceIoService;
    @Resource
    private ReagentStockService reagentStockService;
    @Resource
    private DeviceVoiceService deviceVoiceService;
    @Resource
    private SwitchService switchService;

    public static volatile Boolean process = true;

    @Value("${data.waitTime}")
    private Integer waitTime;

    //翻转屏
    @Value("${flipScree.ip}")
    private String flipIp;

    @Value("${flipScree.port}")
    private String flipPort;

    @Value("${flipScree.open}")
    private String open;

    @Value("${flipScree.close}")
    private String close;

    @Value("${data.serialNo}")
    private String serialNo;

    @Value("${data.url}")
    private String url;

    /**
     * 单人刷脸 虹软调用 进门调用 进门直接是用的线程池
     * @param flag 1开门 2关门
     * @param user 用户对象
     */
    @Override
    public void executeSingle(int flag, SysLoginModel user, DeviceFace faceModel) {
        System.out.println("单人刷脸:ip："+faceModel.getIp() +",线程："+ Thread.currentThread().getName());
        DeviceVoice voiceModel = new DeviceVoice();
        try {
            synchronized (process) {
                if (!process) {
                    log.info("单人刷脸处理繁忙！！");
                    return;
                }
                process = false;
            }

            //获得试剂库id、进行硬件控制
            String warehouseId = "1";
           // voiceModel = deviceVoiceService.getByWarehouseId(warehouseId);
            //刷脸日志记录
            this.addFaceLog(user, flag,warehouseId ,faceModel.getWarehouseName());

            //用房间号开头，避免多库房不能区分FaceUtil
            List<SysLoginModel> userList =  redisUtil.get(warehouseId+"user") == null?new ArrayList<>():(List<SysLoginModel>) redisUtil.get(warehouseId+"user");
            //获取用户列表  1进门

            if (checkUserAdd(user.getId(), userList)) {
                userList.add(user);
                redisUtil.set(warehouseId+"user", userList);
            }
            if (!"1".equals(redisUtil.get(warehouseId+"faceFlag"))) {
                redisUtil.set(warehouseId+"faceFlag", "1");

                voiceUtil.sendVoice("192.168.90.19","50002","验证通过");
                //硬件控制开关 1为开
                SwitchModel hd = switchService.getByCode("HD");
                if(null != hd  && "1".equals(hd.getStatus())){
                    this.openHardWare(warehouseId);
                }
            }else{
                //危化品库里存在人员 不做任何操作 或者只开门关门
                this.openAndCloseDoor(warehouseId);
            }

        } catch (Exception e) {
            e.printStackTrace();
            voiceUtil.sendVoice(voiceModel.getIp(),voiceModel.getPort(),"系统异常");
        } finally {
            process = true;
        }
    }



    /**
     * 双人刷脸业务 暂时不用
     */
    @Override
    public void executeDouble(int flag, SysLoginModel user, DeviceFace faceModel) {
        log.info("双人刷脸线程——" + Thread.currentThread().getName());
        synchronized (process) {
            if (!process) {
                log.info("。。。。面部识别处理繁忙。。。。");
                return;
            }
            process = false;
        }
        String warehouseId = faceModel.getWarehouseId();
        DeviceVoice voiceModel = deviceVoiceService.getByWarehouseId(warehouseId);
        this.addFaceLog(user, flag,warehouseId ,voiceModel.getWarehouseName());
        try {
            if (1 == flag) {//进
                List<SysLoginModel> userList =  redisUtil.get(warehouseId+"userList") == null?new ArrayList<>():(List<SysLoginModel>)redisUtil.get(warehouseId+"userList");
                //人满了 不让进
                if(null != userList  && userList.size() == 2 ){
                    return;
                }
                //查看是否需要添加用户 是新人就加
                if (checkUserAdd(user.getId(), userList)) {
                    userList.add(user);
                    redisUtil.set(warehouseId+"userList", userList);
                }
                //门没开时候是null
                if (!"1".equals(redisUtil.get(warehouseId+"faceLogin"))) {
                    if (userList.size() == 1) {
                        voiceUtil.sendVoice(voiceModel.getIp(),voiceModel.getPort(),"请第二个人刷脸认证");
                        //开启多线程  等待20秒
                        this.waitSecondPersonFaceValid(warehouseId);
                        System.out.println("双人进门等待第二人,主线程结束");
                        return;
                    } else if (userList.size() == 2) {
                        // 刷脸登录成功
                        redisUtil.set(warehouseId +"faceLogin", "1");
                        //开启硬件
                        this.openHardWare(warehouseId);
                        voiceUtil.sendVoice(voiceModel.getIp(),voiceModel.getPort(),"验证通过,请进门!");
                    } else {
                        //直接开门
                       //this.openAndCloseDoor(warehouseId);
                    }
                }else {
                    log.info("室内有人,请稍等！");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            process = true;
        }
    }




    private void addFaceLog(SysLoginModel user,int faceType,String warehouseId,String warehouseName){
        //启动后一个线程 每隔三秒读取一次
        new Thread(){
            public void run(){
                    try{
                        HashMap<String,Object> param = new HashMap<>();
                        param.put("userNo",user.getUserNo());
                        param.put("faceType",faceType+"");//1进门 2出门
                        param.put("createTime",new Date());
                        param.put("userId",user.getId());
                        param.put("realName",user.getRealName());
                        param.put("warehouseId",warehouseId);
                        param.put("warehouseName",warehouseName);
                        faceLogService.addFaceLog(param);
                    }catch (Exception e){
                        throw new CustomException("创建刷脸日志异常!");
                    }

            }
        }.start();

    }

    private boolean checkUserAdd(Integer userId, List<SysLoginModel> list){
        if(null != list && list.size() > 0){
            for(SysLoginModel item :list){
                if(item.getId() == userId){
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 第一个人刷脸并等待第二个人刷
     */
    public void waitSecondPersonFaceValid(String warehouseId) {
        ThreadPoolExecutor threadPool = ThreadPoolUtil.getThreadPool();

        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    log.info(warehouseId+"号房间,等待第二个人刷脸的线程"+Thread.currentThread().getName());
                    Thread.sleep(10000);
                    if (!"1".equals(redisUtil.get("faceLogin"))) {
                        DeviceVoice voiceModel = deviceVoiceService.getByWarehouseId(warehouseId);
                        voiceUtil.sendVoice(voiceModel.getIp(),voiceModel.getPort(), "等待刷脸失效");
                        redisUtil.del(warehouseId+"userList");
                        System.out.println("双人进门等待第二人失败,子线程结束");
                    }
                    System.out.println("双人进门等待第二人成功,子线程结束");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }




    /**
     * 双人开门删除在线用户
     * @param userNo
     * @param userList
     */
    private void delUserOnline(String userNo, List<SysLoginModel> userList,String warehouseId ){
        int delIndex = 0;
        boolean delFlag = false;
        for(int i=0;i<userList.size();i++){
            if(userNo.equals(userList.get(i).getUserNo())){
                delIndex = i;
                delFlag = true;
                break;
            }
        }
        if(delFlag){
            userList.remove(delIndex);
        }
        redisUtil.set(warehouseId+"userList",userList);
    }



    /**
     * 开门 然后全部
     * @param wareHouseId
     */
    private void openAndCloseDoor(String wareHouseId) throws Exception{
        DeviceIo ioModel = new DeviceIo();
        ioModel.setWarehouseId(wareHouseId);
        //查询固定房间开门的IO模块
        ioModel.setSwitchType(2);
        ArrayList<DeviceIo> list = deviceIoService.selectListByModel(ioModel);
        //时间排序，门的IO一定要放在时间靠后的第一路
        String doorIp =list.get(0).getIp();
        String doorPort=list.get(0).getPort();
        // 开启IO模块1命令
        ioUtil.operIo(doorIp,doorPort,"CCDDA10100010001A448");
        //延迟10秒关门
        TimeUnit.SECONDS.sleep(10);
        // 关闭IO模块全部命令
        ioUtil.operIo(doorIp,doorPort,"CCDDA10100000001A346");
    }


    /**
     *  进门  打开硬件
     * @param warehouseId
     */
    private void openHardWare(String warehouseId) throws Exception{
        DeviceIo ioModel = new DeviceIo();
        ioModel.setWarehouseId(warehouseId);
        //查询固定房间开门的IO模块
        ioModel.setSwitchType(1);

/*
        ArrayList<DeviceIo> list = deviceIoService.selectListByModel(ioModel);
        //时间排序，门的IO一定要放在时间靠后的第一路
        String ip =list.get(0).getIp();
        String port=list.get(0).getPort();
        String command=list.get(0).getCommand();
*/

        //全开
        ioUtil.operIo("192.168.90.18","50000","CCDDA101FFFFFFFF9E3C");
        //翻转屏
        ioUtil.operIo(flipIp,flipPort,open);
        //开启录像
        videoService.makeVideo(warehouseId);
        //延迟10秒关门
        TimeUnit.SECONDS.sleep(10);
        // 关闭IO模块1命令
        ioUtil.operIo("192.168.90.18","50000","CCDDA10100000001A346");
    }

    /**
     * 关闭硬件
     * @param wareHouseId
     */
    @Override
    public void closeHardWare(String wareHouseId) throws Exception{
        log.info("出门结算关闭硬件");
        DeviceIo ioModel = new DeviceIo();
        ioModel.setWarehouseId(wareHouseId);
        ioModel.setSwitchType(2);

        ArrayList<DeviceIo> list = deviceIoService.selectListByModel(ioModel);
        String doorIp =list.get(0).getIp().trim();
        String doorPort=list.get(0).getPort().trim();
        String command = list.get(0).getCommand().trim();

        // 开启IO模块1命令  开门
        ioUtil.operIo(doorIp,doorPort,"CCDDA10100010001A448");
        //翻转屏
        ioUtil.operIo(flipIp,flipPort,close);
        //延迟10s秒关门
        Thread.sleep(1000);

        log.info("结算出门 关门命令 ："+ command);
        ioUtil.operIo(doorIp,doorPort,"CCDDA1010000FFFFA040");
        videoService.logout(wareHouseId);
    }

    /**
     * 准备修改 小明程序结算
     * @param list/api/ReagentStock/destroy
     * @return
     * @throws Exception
     */
    @Transactional
    @Override
    public AjaxResult<T> settlement(String warehouseId, List<ReagentStock> list) throws Exception {
        List<ReagentStock> ckList = new ArrayList<>();
        List<ReagentStock> ghList = new ArrayList<>();

        if(null != list && list.size()>0){
            list.forEach(a->{
                if (null != a.getState() && a.getState().equals("1")){//出库
                    ckList.add(a);
                }else if (null != a.getState() && a.getState().equals("2")){//归还
                    ghList.add(a);
                }
            });
        }
        DeviceVoice voiceModel = deviceVoiceService.getByWarehouseId(warehouseId);
        //出库
        if(ckList.size() > 0){
            reagentStockService.batchOutStock(ckList,"admin");
        }
        if(ghList.size() > 0){
            reagentStockService.batchBackStock(ghList,"admin");
        }
        //判断结算成否控制硬件
        voiceUtil.sendVoice(voiceModel.getIp(),voiceModel.getPort(),"结算成功");
        SwitchModel hd = switchService.getByCode("HD");

        if(null != hd  && "1".equals(hd.getStatus())){
            this.closeHardWare("1");
        }
        redisUtil.clearRedisInfo(warehouseId);//清空redis中存储的信息
        return AjaxResult.success();
    }






    //检查用户是否存在
    private static boolean checkIfInLab(String userNo, List<SysLoginModel> userList){
        if(!CollectionUtil.isEmpty(userList)){
            for( SysLoginModel map:userList){
                if(userNo.equals(map.getUserNo())){
                    return true;
                }
            }
        }
        return false;
    }













}
